package hku.cs.eclunuo.util;

import hku.cs.eclunuo.LunuoPlugin;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;

public class LunuoLibHelper {
	/**
     * Returns an array of jar paths contained
     * in the given directory.
     * @param theDirectory the directory to list jars from
     * @return an array of jar paths
     */
    private static IPath[] getJarPathArray(File theDirectory)
    {
        File[] files = theDirectory.listFiles(new JarFilenameFilter());
        IPath[] result = new IPath[files.length];
        for (int i = 0; i < files.length; i++)
        {
            result[i] = new Path(files[i].getAbsolutePath());
        }
        return result;
    }

    /**
     * @return an IPath array of the jar files in client lib directory
     */
    private static IPath[] getClientJarPathArray()
    {
        File clientLibDir = getClientLibPath().toFile();
        return getJarPathArray(clientLibDir);
    }

    /**
     * @return an IPath array of the jar files in client lib directory
     */
    private static IPath[] getCommonJarPathArray()
    {
        File commmonLibDir = getCommonLibPath().toFile();
        return getJarPathArray(commmonLibDir);
    }

    /**
     * @return an array of IClasspathEntry contained in the client dir
     */
    public static IClasspathEntry[] getClientEntries()
    {
        IPath[] clientJars = getClientJarPathArray();
        IClasspathEntry[] result = new IClasspathEntry[clientJars.length];
        for (int i = 0; i < clientJars.length; i++)
        {
            result[i] = getIClasspathEntry(clientJars[i]);
        }
        return result;
    }
    
    

    /**
     * @return an array of IClasspathEntry contained in the common dir
     */
    public static IClasspathEntry[] getCommonEntries()
    {
        IPath[] commonJars = getCommonJarPathArray();
        IClasspathEntry[] result = new IClasspathEntry[commonJars.length];
        for (int i = 0; i < commonJars.length; i++)
        {
            result[i] =  getIClasspathEntry(commonJars[i]);
        }
        return result;
    }

    /**
     * @return an array of IClasspathEntry contained in the common dir
     */
//    public static IClasspathEntry[] getClientSideOnlyEntries()
//    {
//        return getCommonEntries();
//    }
    
    public static IClasspathEntry[] getClientSideWithLibEntries(){
    	IClasspathEntry[] clientEntries = getClientEntries();
        IClasspathEntry[] commonEntries = getCommonEntries();
        return concatenateEntries(clientEntries, commonEntries);
    }


	/**
     * Concatenate two IClasspathEntry arrays.
     * 
     * @param theArray1 the first array
     * @param theArray2 the second array
     * @return an IClasspathEntry array containing the first array
     *         followed by the second one
     */
    public static IClasspathEntry[] concatenateEntries(
        IClasspathEntry[] theArray1, IClasspathEntry[] theArray2)
    {
        IClasspathEntry[] newArray =
            new IClasspathEntry[theArray1.length + theArray2.length];
        System.arraycopy(theArray1, 0, newArray, 0, theArray1.length);
        System.arraycopy(
            theArray2,
            0,
            newArray,
            theArray1.length,
            theArray2.length);
        return newArray;
    }

    /**
     * @return the path to the library directory
     */
    public static IPath getLibPath()
    {        
        try {
				return new Path(FileLocator.toFileURL(LunuoPlugin.getDefault().getBundle().getEntry("/")).getPath());
        }  catch(IOException ex){
        }
        return new Path("lib/");
    }
    
    public static IPath getClientExamplesPath() {
    	return getLibPath().append("examples");
    }

    /**
     * @return the path to the client library directory
     */
    private static IPath getClientLibPath()
    {
        return getLibPath().append("lib");
    }

    /**
     * @return the path to the common library directory
     */
    private static IPath getCommonLibPath()
    {
        return getLibPath();
    }

    /**
     * @param thePath path to convert to an IClasspathEntry
     * @return the IClasspathEntry built from the given path
     */
    public static IClasspathEntry getIClasspathEntry(IPath thePath)
    {
        return JavaCore.newLibraryEntry(thePath, null, null);
    }
    
    /**
     * @param thePath path to convert to an IClasspathEntry
     * @return the IClasspathEntry built from the given path
     */
    public static IClasspathEntry getIClasspathEntry(String thePath)
    {
        return getIClasspathEntry(new Path(thePath));
    }
    
    public static String urlsToString(URL[] urls) {
		StringBuffer cp = new StringBuffer();
		for (URL url : urls) {
			String s = URLDecoder.decode(url.toString());
			cp.append(s.substring(5, s.length()));
			cp.append(File.pathSeparator);
		}
		
		return cp.toString();
	}
    
    public static String[] urlsToStringArray(URL[] urls) {
    	if(urls==null||urls.length==0)
    		return new String[0];
    		
    	String[] cp = new String[urls.length];
    	for(int i=0; i<urls.length; i++){
    		cp[i] = urls[i].toString();   		
    	}
    	return cp;
    }
    
    public static List<IPath> getSourcPathRaletiveProject(IJavaProject javaProject) {
    	IClasspathEntry[] cp;
    	List<IPath> xx = new ArrayList<IPath>();
    	IPath p;
    	try {
    		cp = javaProject.getResolvedClasspath(true);
			for (IClasspathEntry entry : cp) 
				if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
					p = entry.getPath();
					xx.add(p);
				}
			
		} catch (JavaModelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return xx;
		
    }
    
    public static List<IPath> getSourcPath(IJavaProject javaProject) {
    	IClasspathEntry[] cp;
    	List<IPath> xx = new ArrayList<IPath>();
    	IPath p;
    	try {
    		cp = javaProject.getResolvedClasspath(true);
			for (IClasspathEntry entry : cp) 
				if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
					p = entry.getPath();
					xx.add(javaProject.getProject().getWorkspace().getRoot().getLocation().append(p));
				}
			
		} catch (JavaModelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return xx;
		
    }
    
    public static URL[] getSootClassPath(IJavaProject javaProject) {
		IWorkspace workspace = ResourcesPlugin.getWorkspace();
		IClasspathEntry[] cp;
		try {
			cp = javaProject.getResolvedClasspath(true);
			Set<URL> urls = new HashSet<URL>();

			for (IClasspathEntry entry : cp) {
				if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE||
						entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
					URI f;
					if((f=workspace.getRoot().getFile(entry.getPath()).getLocationURI())!=null) {
						URI uri = new URI(f.toString()
							+ "/");
						urls.add(uri.toURL());
					}
					else {
						File file = entry.getPath().toFile();
						URL url = file.toURI().toURL();
						urls.add(url);
					}
				} else {
					File file = entry.getPath().toFile();
					URL url = file.toURI().toURL();
					urls.add(url);
				}
			}
			IClasspathEntry[] lcp = LunuoLibHelper
					.getClientSideWithLibEntries();
			for (IClasspathEntry entry : lcp) {
				File file = entry.getPath().toFile();
				URL url = file.toURI().toURL();
				urls.add(url);
			}

			URL[] array = new URL[urls.size() + 1];
			String uriString = workspace.getRoot().getFile(
					javaProject.getOutputLocation()).getLocationURI()
					.toString()
					+ "/";
			array[0] = new URI(uriString).toURL();
			Iterator<URL> i = urls.iterator();
			int j = 1;
			while (i.hasNext()) {
				array[j] = i.next();
				j++;
			}

			return array;

		} catch (JavaModelException e) {
			e.printStackTrace();
			return new URL[0];
		} catch (MalformedURLException e) {
			e.printStackTrace();
			return new URL[0];
		} catch (URISyntaxException e) {
			e.printStackTrace();
			return new URL[0];
		}
	}
}
